
#include "fieldgenerator.h"
#include "Bot.h"
#include "Logger.h"
#include <math.h>
#include <functional>
#include <map>
#include <queue>
#include <cfloat>
#include <cassert>
#include <algorithm>
#include <stdint.h>

using namespace std;

//constructor
Bot::Bot():field(state)
{

};

//plays a single game of Ants.
void Bot::playGame()
{
    //reads the game parameters and sets up
    Logger::theLogger() << "Reading initial state" << endl;
    cin >> state;
    state.setup();
    endTurn();
    Logger::theLogger() << "Turn 0 completed" << endl;

    //continues making moves while the game is not over
    while(cin >> state)
    {
	Logger::theLogger() << "Starting updateVision" << endl;
        state.updateVisionInformation();
	Logger::theLogger() << "Finished updateVision" << endl;
	Logger::theLogger() << "Starting analyzeMap" << endl;
	state.analyzeMap();
	Logger::theLogger() << "Finished analyzeMap" << endl;
	Logger::theLogger() << "Starting buildSquads" << endl;
	buildSquads();
	Logger::theLogger() << "Finished buildSquads" << endl;
	Logger::theLogger() << "Starting makeMoves" << endl;
        makeMoves();
	Logger::theLogger() << "Finished makeMoves" << endl;
        Logger::theLogger() << state << endl;
        endTurn();
    }
};

void Bot::printSquad(const int& squad_id)  {
    Logger::theLogger() << " squad_id:" << squad_id << ",squad_size:" 
			<< squadList[squad_id].size() << endl;
    Logger::theLogger() << "Ant List:" ;
	    
    for(vector<Location>::const_iterator it = squadList[squad_id].begin();
	it!=squadList[squad_id].end();it++) {
	Logger::theLogger() << "(" << it->row << "," << it->col << "," << state.grid[it->row][it->col].ant << ")" <<  endl;
    }
}

// go through list of ants and group nearby ants in squads
// A squad can be a single ant or upto 10 ants. Each squad
// is scheduled as a unit and moved as unit.
void Bot::buildSquads() {
    clearSquads();
    processedAnts.clear();
    int squad_id =0;
    int SQUAD_SIZE=9999;
    int num_real_squads = 0;
    for (int i=0;i<state.ants.size();i++) {
	if (isInSquad(state.ants[i])) 
	    continue;//skip any ants that are already in squad	
	squad_id++;
	squadList[squad_id].push_back(state.ants[i]);
	inSquad[state.ants[i]] = true;
        continue;
	std::vector<Location> enemyAntList,enemyHillList;
	state.findEnemyAntsInRadius(state.ants[i],state.viewradius,enemyAntList);
	state.findEnemyHillsInRadius(state.ants[i],state.viewradius,enemyHillList);
	if (enemyAntList.size()==0 && enemyHillList.size()==0) {
	    continue;
	}
	std::vector<Location> antList;
	state.findFriendlyAntsInRadius(state.ants[i],state.attackradius*2,antList);
	bool squad_created =false;
	for(std::vector<Location>::iterator it = antList.begin();
	    it!=antList.end();it++){

	    if (isInSquad(*it)) 
		continue;
	    
	    if (squadList[squad_id].size()<SQUAD_SIZE) {
		squadList[squad_id].push_back(*it);
		inSquad[*it] = true;
		squad_created = true;
	    }
	    else {
		break; //this squad is full.
	    }
	}
	if (squad_created)
	    num_real_squads++;
    }
    Logger::theLogger() << "Final number of real squads" << num_real_squads << endl;
}

bool Bot::isInSquad(const Location& loc) const  {
    if (inSquad.find(loc)!=inSquad.end()) 
	return true;
    return false;
}

void Bot::clearSquads() {
    inSquad.clear();
    squadList.clear();
}

bool Bot::findNearbyValidLoc(const Location& loc,Location& validLoc) {
    for (int i=0;i<4;i++) {
	Location nLoc=state.getLocation(loc,i);
	if ((!state.grid[nLoc.row][nLoc.col].isWater) &&
	    (state.grid[nLoc.row][nLoc.col].ant<0)) {
	    validLoc = nLoc;
	    return true;
	}
    }
    return false;
}


void Bot::moveSquad(const int& squad_id) {
    Timer t;
    t.start();
    Logger::theLogger() <<endl <<  "Moving Squad_id: " << squad_id << ", squad_size: " << squadList[squad_id].size() << endl;
    printSquad(squad_id);
    squadMakeExplorers(squad_id);
    Logger::theLogger() << "Finished Moving Squad_id: " << squad_id << ", squad_size: " << squadList[squad_id].size() << endl;
    Logger::theLogger() << "Squad Move took:" << t.getTime() << "ms" << endl;
}


vector<map<Location,int> > Bot::generateMoveVectors(MiniState& miniState,int player_id,const Location& target,
                                                    bool reversePlayer) {
    Logger::theLogger() << "Entering generateMoveVectors" << endl;
    vector<map<Location,int> > moveList;
    if (!reversePlayer && miniState.playerAntList.find(player_id)!=miniState.playerAntList.end()) {
        vector<Location> playerAnts = miniState.playerAntList[player_id];
        map<Location,int> moveTuple;
        for(vector<Location>::iterator it= playerAnts.begin();it!=playerAnts.end();
            it++) {
            if (find(miniState.antsInBattle.begin(),miniState.antsInBattle.end(),*it)==miniState.antsInBattle.end()) 
                continue;

            if (processedAnts.find(*it)!=processedAnts.end()) 
                continue;
            stack<int> path;
            int numNodesExplored;
            miniState.findPath(*it,target,path,numNodesExplored,player_id);
            if (path.empty()) {
                Logger::theLogger() << *it << " has no path to " << target<< endl;
                continue;
            }
            Location nLoc = miniState.getLocation(*it,path.top());
            if (miniState.grid[nLoc.row][nLoc.col].ant<0) {
                moveTuple[*it] = path.top();
                Logger::theLogger() << "generated a move:" <<*it << ":" << CDIRECTIONS[path.top()] << " for player:" << player_id << endl;
            }
        }
        moveList.push_back(moveTuple);
        moveTuple.clear();

        for (vector<Location>::iterator it = playerAnts.begin();
             it!=playerAnts.end();it++) {
            if (find(miniState.antsInBattle.begin(),miniState.antsInBattle.end(),*it)==miniState.antsInBattle.end()) 
                continue;
            if (processedAnts.find(*it)!=processedAnts.end()) 
                continue;

            moveTuple[*it] = -1;
                Logger::theLogger() << "generated a move:" <<*it << ":" << -1 << " for player:" << player_id << endl;

        }
        moveList.push_back(moveTuple);

    }
    else if (reversePlayer) {
        for(map<int,vector<Location> >::iterator it=miniState.playerAntList.begin();it!=miniState.playerAntList.end();it++) {
            if (it->first!=player_id) {
                int cur_player = it->first;
                vector<Location> playerAnts = miniState.playerAntList[it->first];
                map<Location,int> moveTuple;
                for(vector<Location>::iterator it2= playerAnts.begin();it2!=playerAnts.end();
                    it2++) {
                    if (find(miniState.antsInBattle.begin(),miniState.antsInBattle.end(),*it2)==miniState.antsInBattle.end()) 
                        continue;
                    moveTuple[*it2] = -1;
                }
                moveList.push_back(moveTuple);
                // moveTuple.clear();
                // for(int i=0;i<TDIRECTIONS;i++) {
                //     moveTuple.clear();
                //     for(vector<Location>::iterator it2= playerAnts.begin();it2!=playerAnts.end();
                //         it2++) {
                //         Location nLoc = miniState.getLocation(*it2,i);
                //         if ((miniState.grid[nLoc.row][nLoc.col].isWater) ||
                //             (miniState.grid[nLoc.row][nLoc.col].ant==cur_player))
                //             continue;
                //         moveTuple[*it2] = i;
                //     }
                //     moveList.push_back(moveTuple);
                // }
                moveTuple.clear();
                for(vector<Location>::iterator it2= playerAnts.begin();it2!=playerAnts.end();
                    it2++) {
                    if (find(miniState.antsInBattle.begin(),miniState.antsInBattle.end(),*it2)==miniState.antsInBattle.end()) 
                        continue;
                    stack<int> path;
                    int numNodesExplored;
                    miniState.findPath(*it2,target,path,numNodesExplored,it->first);
                    if (path.empty()) {
                        Logger::theLogger() << *it2 << " has no path to " << target<< endl;
                        continue;
                    }
                    Location nLoc = miniState.getLocation(*it2,path.top());
                    if (miniState.grid[nLoc.row][nLoc.col].ant<0) {
                        moveTuple[*it2] = path.top();
                        Logger::theLogger() << "generated a move :" <<*it2 << ":" << CDIRECTIONS[path.top()] << " for player:" << it->first << endl;
                    }
                }
                moveList.push_back(moveTuple);
            }
        }
    }
    Logger::theLogger() << "Finished generateMoveVectors:"<<moveList.size() << endl;

    return moveList;
}

/**run the moves and eval the state and return
 */
float Bot::runMoveList(MiniState miniState,int player_id,const map<Location,int>& moveList) {
    for(map<Location,int>::const_iterator it = moveList.begin();it!=moveList.end();it++) {
        if (it->second!=4) {//4 indicates the ant does not move
            Location nLoc = miniState.getLocation(it->first,it->second);
            if ((!miniState.grid[nLoc.row][nLoc.col].isWater) &&
                (miniState.grid[nLoc.row][nLoc.col].lastSeen!=0) &&
                (miniState.grid[nLoc.row][nLoc.col].ant<0)) {
                miniState.mockMakeMove(it->first,it->second);
            }
        }
    } 
    miniState.resolveBattles();
    return miniState.eval(player_id);
}

map<Location,int> Bot::randomSample(MiniState& miniState,int player_id) {
    float maxVal = -LARGEVAL;
    map<Location,int> bestMoveList;
    map<Location,vector<int> > antMoveCounts;
    for(int i=0;i<30;i++) {
        map<Location,int> moveList;
        for(map<int,vector<Location> >::iterator  playerAntsIt = miniState.playerAntList.begin();playerAntsIt!=miniState.playerAntList.end();
            playerAntsIt++) {
            for (vector<Location>::iterator antIt=playerAntsIt->second.begin();antIt!=playerAntsIt->second.end();antIt++) {
                if (antMoveCounts.find(*antIt)==antMoveCounts.end()) {
                    antMoveCounts[*antIt] = vector<int>();
                    antMoveCounts[*antIt].push_back(1);//N
                    antMoveCounts[*antIt].push_back(1);//E
                    antMoveCounts[*antIt].push_back(1);//S
                    antMoveCounts[*antIt].push_back(1);//W
                    antMoveCounts[*antIt].push_back(1);//No move
                }
                int move = rand()%5;
                moveList[*antIt]=move;
            }
        }
        float val = runMoveList(miniState,player_id,moveList);
        //Now update counts for each ant
        for(map<Location,int>::iterator moveIt=moveList.begin();moveIt!=moveList.end();moveIt++){
            if (val>0) {
                antMoveCounts[moveIt->first][moveIt->second]+=1;
            }
            else {
                antMoveCounts[moveIt->first][moveIt->second]-=1;
            }
        }
    }
    
    for(map<Location,vector<int> >::iterator antCounts=antMoveCounts.begin();
        antCounts!=antMoveCounts.end();antCounts++) {
        if (miniState.grid[antCounts->first.row][antCounts->first.col].ant!=0) 
            continue;
        int curMove=0;
        int curVal=-LARGEVAL;
        for(int i=0;i<antCounts->second.size();i++) {
            if (antCounts->second[i] > curVal) {
                curVal=antCounts->second[i];
                curMove=i;
            }
        }
        if (curMove!=4) {
            bestMoveList[antCounts->first] = curMove;
        }
    }
    return bestMoveList;
    
}

const int  MAX_DEPTH=2;
int Bot::miniMaxDecision(MiniState& miniState,int player_id,const Location& target,
                         map<Location,int>& bestMove) { 
    Logger::theLogger() << "target is :" << target <<endl;
    int alpha,beta;
    alpha = -LARGEVAL;
    beta = LARGEVAL;
    int maxUtility = maxValue(miniState,player_id,1,target,bestMove,alpha,beta);
    //somehow need to extract what lead to maxValue?
    Logger::theLogger() << "maxUtility is:" << maxUtility << endl;
    Logger::theLogger() << "Finished miniMaxDecision" << endl;
    return maxUtility;
}

int Bot::maxValue(MiniState miniState,int player_id,int depth,
                  const Location& target,map<Location,int>& maxMove,
                  int alpha,int beta) {
    Logger::theLogger() << "Entered maxValue:"<<depth << endl;
    Logger::theLogger() << miniState ;
    int cachedScore;
    if (depth>MAX_DEPTH){ 
        Logger::theLogger() <<"Exiting maxValue:"<<depth << endl;
        return  miniState.eval(player_id);
    }
    vector<map<Location,int> > moveList;
    int bestMoveVal=-LARGEVAL;
    map<Location,int> bestMove;
    moveList = generateMoveVectors(miniState,player_id,target,false);
    Logger::theLogger() << "Got moveList of size:" << moveList.size() << endl;
    if (moveList.empty()) {
        Logger::theLogger() <<"Exiting maxValue:"<<depth <<"moveList is empty" << endl;
        return miniState.eval(player_id);
    }
    for(vector<map<Location,int> >::iterator it=moveList.begin();it!=moveList.end();
        it++) {
        stack<pair <pair<Location,int>,int> > moveStack;
        Logger::theLogger() << "making copy" << endl;
        Logger::theLogger() << miniState<< endl;
        MiniState miniStateCp = miniState;
        Logger::theLogger() << "copied state" << endl;
        Logger::theLogger() << miniStateCp;
        Logger::theLogger() << "Going to Apply moves:" << it->size() << endl;
        for(map<Location,int>::iterator it2 = it->begin();it2!=it->end();it2++) {
            if (it2->second<0) {
                //dummy moves to indicate no movement 
                Logger::theLogger() << "Skipping Dummy Move:" << it2->first << ":" << it2->second << endl;
                continue;
            }
            Logger::theLogger() << "Applying Move:" << it2->first << ":" << CDIRECTIONS[it2->second] << endl;
            int saveAnt =  miniStateCp.mockMakeMove(it2->first,it2->second);
            // moveStack.push(pair<pair<Location,int>,int>(*it2,saveAnt));
        }
        Logger::theLogger() << "Done  Applying moves" << endl;

        Logger::theLogger() << miniStateCp ;

        //now updated miniState remove any ants
        map<Location,int> tmpMove;
        int moveVal = minValue(miniStateCp,player_id,depth+1,target,tmpMove,alpha,beta);
        Logger::theLogger() << "maxValue:moveVal:" << moveVal<< ",bestMoveVal:" << bestMoveVal<<endl;
        if (moveVal > bestMoveVal) {
            bestMoveVal = moveVal;
            bestMove = *it;
            if (bestMoveVal>=beta) {
                maxMove = bestMove;
                Logger::theLogger() <<"pruned due to beta cutoff:bestMoveVal:"<<bestMoveVal<<",beta:" << beta << endl;
                return bestMoveVal;
            }
            alpha = (alpha>bestMoveVal)?alpha:bestMoveVal;
        }
        // while(!moveStack.empty()) {
        //     pair< pair<Location,int>, int > move = moveStack.top();
        //     moveStack.pop();
        //     miniState.unmakeMockMove(move.first.first,move.first.second,move.second);
        // }
    }
    maxMove = bestMove;
    Logger::theLogger() << "Exiting maxValue:"<<depth << endl;

    return bestMoveVal;
}

int Bot::minValue(MiniState miniState,int player_id,int depth,
                  const Location& target,map<Location,int>& maxMove,
                  int alpha,int beta) {
    Logger::theLogger() << "Entered minValue: "<<depth << endl;
    Logger::theLogger() << miniState ;
    int cachedScore;

    if (depth>MAX_DEPTH+1) {
        Logger::theLogger() << "Exiting minValue:" << depth <<endl;
        return miniState.eval(player_id);
    }
    
    vector<map<Location,int> > moveList;
    int bestMoveVal=LARGEVAL;
    map<Location,int> bestMove;
    moveList = generateMoveVectors(miniState,player_id,target,true);
    if (moveList.empty()) {
        Logger::theLogger() <<"Exiting minValue:"<<depth <<"moveList is empty" << endl;
        return miniState.eval(player_id);
    }
    for(vector<map<Location,int> >::iterator it=moveList.begin();it!=moveList.end();
        it++) {
        stack<pair <pair<Location,int>,int> > moveStack;
        Logger::theLogger() << "making copy" << endl;
        Logger::theLogger() << miniState;
        MiniState miniStateCp = miniState;
        Logger::theLogger() << "copied state" << endl;
        Logger::theLogger() << miniStateCp;
        for(map<Location,int>::iterator it2 = it->begin();it2!=it->end();it2++) {
            if (it2->second <0) {//dummy  moves to indicate no movement of ants
                Logger::theLogger() << "Skipping Dummy Move:" << it2->first << ":" << it2->second << endl;
                continue;
            }
            Logger::theLogger() << "Applying Move:" << it2->first << ":" << CDIRECTIONS[it2->second] << endl;
            int saveAnt =  miniStateCp.mockMakeMove(it2->first,it2->second);
            //     moveStack.push(pair<pair<Location,int>,int>(*it2,saveAnt));
        }
        Logger::theLogger() << "Done  Applying moves" << endl;

        Logger::theLogger() << miniStateCp ;
        //miniStateCp.resolveBattles();
        //Logger::theLogger() << miniStateCp ;

        map<Location,int> tmpMove;
        int moveVal = maxValue(miniStateCp,player_id,depth+1,target,tmpMove,alpha,beta);
        Logger::theLogger() << "minValue:moveVal:" << moveVal << ",bestMoveVal:" << bestMoveVal<<endl;
        
        if (moveVal < bestMoveVal) {
            bestMoveVal = moveVal;
            bestMove = *it;
        }
        if (bestMoveVal<alpha) {
            maxMove = bestMove;
            return bestMoveVal;
        }
        beta = (beta<bestMoveVal)?beta:bestMoveVal;

        // while(!moveStack.empty()) {
        //     pair< pair<Location,int>, int > move = moveStack.top();
        //     moveStack.pop();
        //     miniState.unmakeMockMove(move.first.first,move.first.second,move.second);
        // }
    }
    maxMove = bestMove;
    Logger::theLogger() << "Exiting minValue:" << depth << endl;
    return bestMoveVal;
}

bool Bot::moveSquadTo2(const vector<Location>::iterator& start,
                      const vector<Location>::iterator& end,
                      const Location& loc,int& moveCnt) {
    vector<Location> allAnts;
    queue<Location> antsToExpand;
    for(vector<Location>::iterator it=start;it!=end;it++) {
        //allAnts.push_back(*it);
        antsToExpand.push(*it);
    }
    antsToExpand.push(loc);
    //allAnts.push_back(loc);
    //antsToExpand(*it);
    set<Location> closedAnts;
    while(!antsToExpand.empty()) {
        Location curLoc= antsToExpand.front();
        antsToExpand.pop();
        closedAnts.insert(curLoc);
        vector<Location> antList;
        state.findThisAntsEnemiesInRadius(curLoc,state.attackradius+2,antList,state.grid[curLoc.row][curLoc.col].ant);
        if (!antList.empty()) {
            for(vector<Location>::iterator it=antList.begin();it!=antList.end();it++) {
                if (closedAnts.find(*it)==closedAnts.end()) {
                    antsToExpand.push(*it);
                }
            }
        }
    }
    int minRow;
    int minCol;
    int maxRow;
    int maxCol;
    bool first = true;
    for(set<Location>::iterator it=closedAnts.begin();it!=closedAnts.end();it++) {
        if (first) {
            minRow = it->row;
            minCol = it->col;
            maxRow = it->row;
            maxCol = it->col;
            first =false;
        }
        else {

            if (it->row <minRow) 
                minRow =it->row;
            if (it->col < minCol)
                minCol =it->col;
            if (it->row > maxRow) 
                maxRow = it->row;
            if (it->col > maxCol) 
                maxCol = it->col;
        }
        allAnts.push_back(*it);
        Logger::theLogger() << "Adding ant to MiniState: " << *it << endl;
    }
        
    //sort all the ants.
    ::sort(allAnts.begin(),allAnts.end());
    Location mapCoord1 = Location(minRow,minCol);
    Location mapCoord2 = Location(maxRow,maxCol);
    //expand the rectangle by attackradius*2.
    mapCoord1.row -=(state.attackradius*2 + 1);
    mapCoord1.col -=(state.attackradius*2 + 1);
    mapCoord2.row +=(state.attackradius*2 + 1);
    mapCoord2.col +=(state.attackradius*2 + 1);
    
    Logger::theLogger() << "Moving Squad to " << loc << endl;

    Logger::theLogger() << " creating miniState from mapCoord1:" << mapCoord1 <<",mapCoord2:" << mapCoord2 << endl;
    MiniState miniState(&state,mapCoord1,mapCoord2,allAnts);
    Logger::theLogger() << "miniState created" << endl;
    //map<Location,int> moveList = randomSample(miniState,0);
    map<Location,int> moveList;
    int maxUtility= miniMaxDecision(miniState,0,Location(loc.row-mapCoord1.row,loc.col-mapCoord1.col),moveList);
    Logger::theLogger() <<"miniMaxDecision returned for loc:" << loc << endl;
    Logger::theLogger() << miniState ;
    if (maxUtility<0) {
        Logger::theLogger() << "moveSquadTo2::bad_move:maxUtility:" << maxUtility << endl;
        return false;
    }
    moveCnt=0;
    for(map<Location,int>::iterator it= moveList.begin();it!=moveList.end();it++) {
        pair<Location,int> move = miniState.translateMoveToMainMap(*it);
        if (move.second<0) //dummy move
            continue;
        Logger::theLogger() << it->first <<":" << CDIRECTIONS[it->second] << endl;
        Logger::theLogger() << move.first <<":" << CDIRECTIONS[move.second] << endl;
        safeMakeMove(move.first,move.second);
        moveCnt++;
    }
    if (maxUtility>0) {
        for(vector<Location>::iterator antIt = allAnts.begin();antIt!=allAnts.end();
            antIt++) {
            //add any ants included in the minimax to processedAnts. don't want
            //to move ants that may have been a part of this decision
            //even if they didn't move via safeMakeMove;
            if (state.grid[antIt->row][antIt->col].ant ==0) {
                processedAnts[*antIt]=true;
            }
        }
    }
    return true;
}


bool Bot::shouldAttack() const{
    return true;
    if (state.knownLandPercent<0.5) {
	return false;
    }
    //compute number of ants we control vs number of visible enemies
    double antRatio = (double)state.ants.size()/state.enemies.size();
    if (antRatio < 1.2) 
	return false;
    return true;
}

void Bot::safeMakeMove(const Location& ant,int direction) {
    if (state.grid[ant.row][ant.col].ant!=0) 
        return;
    Logger::theLogger()<<state;
    Location nLoc = state.getLocation(ant,direction);
    if ((processedAnts.find(ant)==processedAnts.end()) &&
        (state.grid[nLoc.row][nLoc.col].ant<0) &&
	(!state.grid[nLoc.row][nLoc.col].isWater)) {
	state.makeMove(ant,direction);
        Logger::theLogger()<<state;
	state.antWalkMap[nLoc] = state.antWalkMap[ant];
	state.antWalkMap.erase(ant);
        processedAnts[nLoc] = true;
    }
    else {
	Logger::theLogger() << "safeMakeMove, move would kill an ant " << ant << ":" << CDIRECTIONS[direction] << endl;
        processedAnts[ant] = true;
    }
}

void Bot::antMakeExplorer(const Location& loc) {
    explorers.push_back(loc);
}

void Bot::squadMakeExplorers(const int& squad_id) {
    for(int i=0;i<squadList[squad_id].size();i++) {
	Location ant  = squadList[squad_id][i];
        if (state.ants.size()>10 && (state.myHills.size()>0)) {
            Location hill;
            if (state.myHillInView(ant,state.viewradius,hill)) {
                vector<Location> antList;
                state.findFriendlyAntsInRadius(hill,state.viewradius,antList);
                if (antList.size()>=1) {
                    Logger::theLogger() << "Making explorer:" << ant << endl;
                    antMakeExplorer(ant);
                }
            }
            else {
                Logger::theLogger() << "Making explorer:" << ant << endl;
                antMakeExplorer(ant);
            }
        }
        else {
            Logger::theLogger() << "Making explorer:" << ant << endl;
            antMakeExplorer(ant);
        }
    }
}


void Bot::multiSourceBFSHelper(const State::BFSQueueMode& queueMode) {
    State::MoveMap antMoves;
    Logger::theLogger() << "Starting state.multiSourceBFSFindMove" << endl;
    state.multiSourceBFSFindMove(explorers,antMoves,queueMode);
    Logger::theLogger() << "Finished state.multiSourceBFSFindMove" << endl;
    for (State::MoveMap::iterator it= antMoves.begin();
         it!= antMoves.end();it++) {
        Logger::theLogger() << it->first.first << ":" << it->first.second << 
            ":" << CDIRECTIONS[it->second] << endl;
    }
    int moveCnt =0;
    for (State::MoveMap::iterator it= antMoves.begin();
         it!= antMoves.end();it++) {
        Timer t;
        t.start();
        Logger::theLogger() <<"Processing Explorer ant :" << it->first.first << endl;
        if (processedAnts.find(it->first.first)!=processedAnts.end()) {
            Logger::theLogger() << "Ant:" << it->first.first<< " already processed skipping" << endl;
            continue;
        }
        if ((queueMode==State::FOOD) &&
            moveCnt==state.food.size()) {
            Logger::theLogger() << "all food being harvested , stop processing ants" << endl;
            break;
        }
        if (queueMode==State::ENEMIES) { 
            Logger::theLogger() << "moveval: " << it->first.second << endl;
            if (it->first.second>6) {
                Logger::theLogger() << "all enemies being targetted, stop processing ants" << endl;
                break;
            }
        }
        if (queueMode==State::MYHILLS) {
            Logger::theLogger() << "moveval:" << it->first.second << endl;
            if (it->first.second>10) {
                break;
            }
        }

        if (queueMode==State::ENEMYHILLS) {
            Logger::theLogger() << "moveval:" << it->first.second << endl;
            if (it->first.second>20) {
                break;
            }
        }
        Location nLoc = state.getLocation(it->first.first,it->second);
        vector<Location> enemyAntList;
        state.findEnemyAntsInRadius(nLoc,state.attackradius+2,enemyAntList);
        if (enemyAntList.size()==0) {
            safeMakeMove(it->first.first,it->second);
            moveCnt++;
            continue;
        }
        vector<Location> antList;
        antList.push_back(it->first.first);
        int squadMoveCount=0;
        if (!moveSquadTo2(antList.begin(),antList.end(),nLoc,squadMoveCount)) {
            Logger::theLogger() <<"Ant is probably in an unsafe location,try and move it" << endl;
            if (!moveSquadTo2(antList.begin(),antList.end(),*antList.begin(),squadMoveCount)) {
                for(int d=0;d<TDIRECTIONS;d++) {
                    Location escapeLoc = state.getLocation(it->first.first,d);
                    Logger::theLogger() << "Escape attempt :" << d << " to " << escapeLoc << "for ant at:" << it->first.first << endl;
                    if (state.grid[escapeLoc.row][escapeLoc.col].isWater ||
                        (state.grid[escapeLoc.row][escapeLoc.col].ant>=0)) {
                        Logger::theLogger() << "way is blocked skipping" << endl;
                        continue;
                    }
                    if (moveSquadTo2(antList.begin(),antList.end(),escapeLoc,squadMoveCount)) {
                        moveCnt+=squadMoveCount;
                        Logger::theLogger() << "Successful escape" << endl;
                        break;
                    }
                }
                Logger::theLogger() << "Ant escape code completed" << endl;
            }
            else {
                moveCnt+=squadMoveCount;
            }
        }
        else {
            moveCnt+=squadMoveCount;
        }
        Logger::theLogger() << "Processed Explorer ant:" << it->first.first << " in " << t.getTime() << "ms" << endl;
    }
}

void Bot::multiSourceBFSExplore() {
    if (explorers.empty()) {
        Logger::theLogger() << "Explorer list is empty, do nothing" << endl;
        return;
    }
    Logger::theLogger() << "Start multiSourcesBFSMode:MYHILLS" << endl;
    multiSourceBFSHelper(State::MYHILLS);
    Logger::theLogger() << "Finished multiSourcesBFSMode:MYHILLS" << endl;

    Logger::theLogger() << "Start multiSourcesBFSMode:FOOD" << endl;
    multiSourceBFSHelper(State::FOOD);
    Logger::theLogger() << "Finished multiSourcesBFSMode:FOOD" << endl;


    Logger::theLogger() << "Start multiSourcesBFSMode:ENEMYHILLS" << endl;
    multiSourceBFSHelper(State::ENEMYHILLS);
    Logger::theLogger() << "Finished multiSourcesBFSMode:ENEMYHILLS" << endl;


    Logger::theLogger() << "Start multiSourcesBFSMode:ENEMIES" << endl;
    multiSourceBFSHelper(State::ENEMIES);
    Logger::theLogger() << "Finished multiSourcesBFSMode:ENEMIES" << endl;

    Logger::theLogger() << "Start multiSourcesBFSMode:FRONTIER" << endl;
    multiSourceBFSHelper(State::FRONTIER);
    Logger::theLogger() << "Finished multiSourcesBFSMode:FRONTIER" << endl;
}

bool Bot::isFoodAdjacent(const Location& loc) {
    for(int d=0; d<TDIRECTIONS; d++)
    {
	Location nLoc = state.getLocation(loc, d);
	if (state.grid[nLoc.row][nLoc.col].isFood)
	    return true;
    }
    return false;
}


//makes the bots moves for the turn
void Bot::makeMoves()
{
    Logger::theLogger() << "turn " << state.turn << ":" << endl;
    Logger::theLogger() << state << endl;


    //pick out moves per squad
    for (map< int, vector<Location> >::iterator it=squadList.begin();
	 it!=squadList.end();
	 it++) {
	moveSquad(it->first);
    }
    //Finally move all explorers in one sweep
    Logger::theLogger() << "starting multiSourceBFSExploration at " << state.timer.getTime() << "ms" << endl;
    multiSourceBFSExplore();
    Logger::theLogger() << "BFS Exploration took:" << state.timer.getTime() << "ms" << endl;

    Logger::theLogger() << "Move time taken: " << state.timer.getTime() << "ms" << endl << endl;
};

//finishes the turn
void Bot::endTurn()
{
    if(state.turn > 0) {
        state.reset();
        explorers.clear();
    }
    state.turn++;

    cout << "go" << endl;
};
